package com.demo.test.utils;

import cn.hutool.core.util.NumberUtil;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.math.BigInteger;

/**
 * XWPFTable 增强工具类 <br/>
 *
 * <ul>
 * <li>合并行单元格</li>
 * <li>合并列单元格</li>
 * <li>设置每列宽度</li>
 * <li>边框大小</li>
 * </ul>
 *
 * @author Sayi
 * @version 1.4.0
 */
public final class TableTools {

    /**
     * 合并行单元格
     *
     * @param table   表格对象
     * @param row     行 从0开始
     * @param fromCol 起始列
     * @param toCol   结束列
     */
    public static void mergeCellsHorizonal(XWPFTable table, int row, int fromCol, int toCol) {
        if (toCol <= fromCol) return;
        XWPFTableCell cell = table.getRow(row).getCell(fromCol);
        CTTcPr tcPr = getTcPr(cell);
        XWPFTableRow rowTable = table.getRow(row);
        for (int colIndex = fromCol + 1; colIndex <= toCol; colIndex++) {
            rowTable.getCtRow().removeTc(fromCol + 1);
            rowTable.removeCell(fromCol + 1);
        }

        tcPr.addNewGridSpan();
        tcPr.getGridSpan().setVal(BigInteger.valueOf((long) (toCol - fromCol + 1)));
    }

    /**
     * 合并列单元格
     *
     * @param table   表格对象
     * @param col     列 从0开始
     * @param fromRow 起始行
     * @param toRow   结束行
     */
    public static void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {
        if (toRow <= fromRow) return;
        for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
            XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
            CTTcPr tcPr = getTcPr(cell);
            CTVMerge vMerge = tcPr.addNewVMerge();
            if (rowIndex == fromRow) {
                // The first merged cell is set with RESTART merge value
                vMerge.setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one, are set with CONTINUE
                vMerge.setVal(STMerge.CONTINUE);
            }
        }
    }

    /**
     * 设置表格每列的宽度
     *
     * @param table     表格对象
     * @param colWidths 每列的宽度，单位CM
     */
    @SuppressWarnings("unused")
    // TODO
    public static void widthTable(XWPFTable table, float[] colWidths) {
        float widthCM = 0;
        for (float w : colWidths) {
            widthCM += w;
        }
        long width = (int) (widthCM / 2.54 * 1440);
        CTTblPr tblPr = getTblPr(table);
        CTTblWidth tblW = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();
        tblW.setType(0 == width ? STTblWidth.AUTO : STTblWidth.DXA);
        tblW.setW(BigInteger.valueOf(width));

        if (0 != width) {
            CTTblGrid tblGrid = table.getCTTbl().getTblGrid();
            if (null == tblGrid) {
                tblGrid = table.getCTTbl().addNewTblGrid();
            }

            for (float w : colWidths) {
                CTTblGridCol addNewGridCol = tblGrid.addNewGridCol();
                addNewGridCol.setW(BigInteger.valueOf((long) (w / 2.54 * 1440)));
            }
        }
    }

    /**
     * 设置表格每列的宽度
     *
     * @param table       表格对象
     * @param colPercents 每列的百分比
     */
    @SuppressWarnings("unused")
    // TODO
    public static void widthTable(XWPFTable table, float widthCM, double[] colPercents) {
        int width = (int) (widthCM / 2.54 * 1440);
        CTTblPr tblPr = table.getCTTbl().getTblPr();
        if (null == tblPr) {
            tblPr = table.getCTTbl().addNewTblPr();
        }
        CTTblWidth tblW = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();
        tblW.setType(0 == width ? STTblWidth.AUTO : STTblWidth.DXA);
        tblW.setW(BigInteger.valueOf(width));

        if (0 != width) {
            CTTblGrid tblGrid = table.getCTTbl().getTblGrid();
            if (null == tblGrid) {
                tblGrid = table.getCTTbl().addNewTblGrid();
            }

            for (double colPercent : colPercents) {
                CTTblGridCol addNewGridCol = tblGrid.addNewGridCol();
                addNewGridCol.setW(BigInteger.valueOf((long) NumberUtil.mul(width, colPercent)));
            }
        }
    }

    /**
     * 表格设置宽度，每列平均分布
     *
     * @param table
     * @param widthCM
     * @param cols
     */
    public static void widthTable(XWPFTable table, float widthCM, int cols) {
        int width = (int) (widthCM / 2.54 * 1440);
        CTTblPr tblPr = table.getCTTbl().getTblPr();
        if (null == tblPr) {
            tblPr = table.getCTTbl().addNewTblPr();
        }
        CTTblWidth tblW = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();
        tblW.setType(0 == width ? STTblWidth.AUTO : STTblWidth.DXA);
        tblW.setW(BigInteger.valueOf(width));

        if (0 != width) {
            CTTblGrid tblGrid = table.getCTTbl().getTblGrid();
            if (null == tblGrid) {
                tblGrid = table.getCTTbl().addNewTblGrid();
            }

            for (int j = 0; j < cols; j++) {
                CTTblGridCol addNewGridCol = tblGrid.addNewGridCol();
                addNewGridCol.setW(BigInteger.valueOf(width / cols));
            }
        }
    }

    /**
     * 设置Cell文本
     *
     * @param cell
     * @param text
     */
    public static void setCellText(XWPFTableCell cell, String text) {
        CTTc cttc = cell.getCTTc();

        CTTcPr cellPr = cttc.addNewTcPr();
        cellPr.addNewVAlign().setVal(STVerticalJc.CENTER);

        cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);

        //通常这会在单元格中添加一个段落，但单元格已经有一个。因此，首先删除单元格中的段落，然后添加新段落，否则结果将在新段落之前为空行
        WordHolder wordHolder = new WordHolder();
        wordHolder.getRunBuilder().init(getCellFirstParagraph(cell).createRun()).content(text)
                .font("楷体", "Times New Roman", "20")
                .bold(false).italic(false).strike(false).position(0).space(0);
    }

    /**
     * 得到单元格第一个Paragraph
     *
     * @param cell
     * @return XWPFParagraph
     */
    public static XWPFParagraph getCellFirstParagraph(XWPFTableCell cell) {
        XWPFParagraph p;
        if (cell.getParagraphs() != null && cell.getParagraphs().size() > 0) {
            p = cell.getParagraphs().get(0);
        } else {
            p = cell.addParagraph();
        }
        return p;
    }


    /**
     * 设置根据行列位置cell文本
     *
     * @param table
     * @param rowPosition
     * @param colPosition
     */
    public static XWPFTableCell getCell(XWPFTable table, int rowPosition, int colPosition) {
        if (table == null) {
            throw new IllegalStateException("the XWPFTable 不能为空");
        }

        int tableRowsNum = table.getNumberOfRows();

        if (rowPosition < 0 || colPosition < 0) {
            throw new IllegalArgumentException("参数非法，应该大于等于0");
        }

        if (tableRowsNum < rowPosition + 1) {
            throw new IllegalArgumentException("rowPosition大于实际的表格行数");
        }

        int tableColsNum = table.getRow(0).getTableCells().size();
        if (tableColsNum < colPosition + 1) {
            throw new IllegalStateException("colPosition大于实际的表格列数");
        }

        return table.getRow(rowPosition).getCell(colPosition);
    }

    /**
     * 获取列宽
     *
     * @param table
     * @param colIndex
     * @return
     */
    public static BigInteger getColWidth(XWPFTable table, int colIndex) {
        return table.getCTTbl().getTblGrid().getGridColArray(colIndex).getW();
    }

    /**
     * 获取列宽
     *
     * @param cell
     * @return
     */
    // TODO 此方法待研究，会报NullPointerException
    @Deprecated
    public static BigInteger getColWidth(XWPFTableCell cell) {
        return getTcPr(cell).getTcW().getW();
    }

    /**
     * 设置表格总宽度
     *
     * @param table
     * @param width
     */
    public static void widthTable(XWPFTable table, BigInteger width) {
        CTTbl ttbl = table.getCTTbl();
        CTTblPr tblPr = ttbl.getTblPr() == null ? ttbl.addNewTblPr() : ttbl.getTblPr();

        tblPr.addNewTblLayout().setType(STTblLayoutType.FIXED);

        CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();

        CTJc cTJc = tblPr.addNewJc();
        cTJc.setVal(STJc.CENTER);
        tblWidth.setType(STTblWidth.DXA);
        tblWidth.setW(width);
    }

    //  ---表格样式相关---

    /**
     * 表格布局设置
     *
     * @param table
     * @param layoutEnum
     */
    public static void setTableLayout(XWPFTable table, STTblLayoutType.Enum layoutEnum) {
        CTTblPr tblPr00 = getTblPr(table);
        CTTblLayoutType layoutType = tblPr00.isSetTblLayout() ? tblPr00.getTblLayout() : tblPr00.addNewTblLayout();
        layoutType.setType(layoutEnum);
    }

    /**
     * 设置表格边框
     *
     * @param table
     * @param size
     */
    public static void borderTable(XWPFTable table, int size, STBorder.Enum stBorder, TableRowAlign tableRowAlign) {
        CTTblPr tblPr = getTblPr(table);
        CTTblBorders tblBorders = tblPr.getTblBorders();
        BigInteger borderSize = BigInteger.valueOf(size);
        tblBorders.getBottom().setSz(borderSize);
        tblBorders.getLeft().setSz(borderSize);
        tblBorders.getTop().setSz(borderSize);
        tblBorders.getRight().setSz(borderSize);
        tblBorders.getInsideH().setSz(borderSize);
        tblBorders.getInsideV().setSz(borderSize);

        tblBorders.getBottom().setVal(stBorder);
        tblBorders.getLeft().setVal(stBorder);
        tblBorders.getTop().setVal(stBorder);
        tblBorders.getRight().setVal(stBorder);
        tblBorders.getInsideH().setVal(stBorder);
        tblBorders.getInsideV().setVal(stBorder);

        //Sets alignment values allowed for Tables and Table Rows
        table.setTableAlignment(tableRowAlign);
    }

    /**
     * 设置表格边框
     *
     * @param table
     * @param stBorder
     * @param tableRowAlign
     */
    public static void borderTable(XWPFTable table, STBorder.Enum stBorder, TableRowAlign tableRowAlign) {
        CTTblPr tblPr = getTblPr(table);
        CTTblBorders tblBorders = tblPr.getTblBorders();
        tblBorders.getBottom().setVal(stBorder);
        tblBorders.getLeft().setVal(stBorder);
        tblBorders.getTop().setVal(stBorder);
        tblBorders.getRight().setVal(stBorder);
        tblBorders.getInsideH().setVal(stBorder);
        tblBorders.getInsideV().setVal(stBorder);

        table.setTableAlignment(tableRowAlign);
    }

    //  ---获取属性相关---
    private static CTTblPr getTblPr(XWPFTable table) {
        CTTblPr tblPr = table.getCTTbl().getTblPr();
        if (null == tblPr) {
            tblPr = table.getCTTbl().addNewTblPr();
        }
        return tblPr;
    }

    private static CTTcPr getTcPr(XWPFTableCell cell) {
        CTTcPr tcPr = cell.getCTTc().isSetTcPr() ? cell.getCTTc().getTcPr()
                : cell.getCTTc().addNewTcPr();
        return tcPr;
    }

    /**
     * @Description: 得到CTTrPr, 不存在则新建
     */
    public CTTrPr getTrPr(XWPFTableRow row) {
        CTRow ctRow = row.getCtRow();
        CTTrPr trPr = ctRow.isSetTrPr() ? ctRow.getTrPr() : ctRow.addNewTrPr();
        return trPr;
    }
}
